﻿using System.Text;
using RpcCentral.Collect.Model;
using RpcCentral.Common;
using RpcCentral.DAL;
using RpcCentral.Model;
using WeDonekRpc.Helper;
using WeDonekRpc.Model;

namespace RpcCentral.Collect.Helper
{
    internal class TransmitHelper : ITransmitHelper
    {
        private static readonly long _HashCodeSum = 4294967295;
        private static readonly int _ZoneIndexSum = 79;

        private readonly IServerTransmitConfigDAL _TransmitConfig;
        private readonly IRemoteServerGroupDAL _ServerGroup;

        public TransmitHelper (IServerTransmitConfigDAL transmitConfig, IRemoteServerGroupDAL serverGroup)
        {
            this._TransmitConfig = transmitConfig;
            this._ServerGroup = serverGroup;
        }

        private long[] _ServerId;
        private string _GetVer (ServerTransmitScheme[] configs, long rpcMerId, long systemType)
        {
            StringBuilder str = new StringBuilder();
            List<long> serverId = [];
            bool isLoad = false;
            configs.ForEach(a =>
            {
                _ = str.Append(a.Id);
                _ = str.Append(',');
                _ = str.Append(a.VerNum);
                if (a.IsAuto == false)
                {
                    a.Transmit.ForEach(c =>
                    {
                        serverId.Add(c.ServerId);
                    });
                }
                else
                {
                    isLoad = true;
                }
            });
            if (isLoad)
            {
                this._ServerId = this._ServerGroup.GetRemoteServerId(rpcMerId, systemType);
                serverId.AddRange(this._ServerId);
            }
            if (serverId.Count > 0)
            {
                long[] ids = serverId.Distinct().OrderBy(a => a).ToArray();
                _ = str.Append('_');
                _ = str.AppendJoin(',', ids);
            }
            return str.ToString().GetMd5();
        }
        public bool GetTransmits (long rpcMerId, long systemType, ref string ver, out Transmit[] transmits)
        {
            ServerTransmitScheme[] configs = this._TransmitConfig.Gets(systemType, rpcMerId);
            if (configs.Length == 0)
            {
                transmits = Array.Empty<Transmit>();
                return ver == string.Empty;
            }
            string newVer = this._GetVer(configs, rpcMerId, systemType);
            if (newVer == ver)
            {
                transmits = null;
                return false;
            }
            List<Transmit> list = [];
            configs.ForEach(a =>
            {
                if (a.IsAuto)
                {
                    this._AutoGenerate(list, a);
                }
                else
                {
                    this._InitTransmit(a, list);
                }
            });
            transmits = list.OrderByDescending(a => a.Sort).Distinct().ToArray();
            ver = newVer;
            return true;
        }
        private void _InitTransmit (ServerTransmitScheme scheme, List<Transmit> list)
        {
            foreach (ServerTransmitConfig config in scheme.Transmit)
            {
                config.TransmitConfig.ForEach(d =>
                {
                    list.Add(new Transmit
                    {
                        Range = d.Range,
                        Scheme = scheme.Scheme,
                        TransmitType = scheme.TransmitType,
                        Value = d.Value,
                        ServerId = config.ServerId,
                        Sort = 100
                    });
                });
            }
        }
        private void _InitHashCode (List<Transmit> transmits, ServerTransmitScheme config)
        {
            if (this._ServerId.Length == 1)
            {
                transmits.Add(new Transmit
                {
                    Range = new TransmitRange[]
                    {
                        new TransmitRange
                        {
                            BeginRange = int.MinValue,
                            EndRange = int.MaxValue
                        }
                    },
                    Scheme = config.Scheme,
                    TransmitType = config.TransmitType,
                    ServerId = this._ServerId[0]
                });
            }
            else
            {
                this._InitTransmit(_HashCodeSum, int.MinValue, (long)int.MaxValue + 1, transmits, config);
            }
        }
        private void _InitTransmit (long sum, long begin, long max, List<Transmit> transmits, ServerTransmitScheme config)
        {
            int num = (int)( this._ServerId.Length * RpcContralConfig.TransmitScale );
            if (num == 0)
            {
                return;
            }
            long size = sum / num;
            int len = this._ServerId.Length;
            long endId = this._ServerId[this._ServerId.Length - 1];
            Dictionary<long, List<TransmitRange>> dics = [];
            for (int k = 0; k < num; k++)
            {
                long i = this._ServerId[k % len];
                long end = i == endId ? max : begin + size;
                if (dics.TryGetValue(i, out List<TransmitRange> ranges))
                {
                    ranges.Add(new TransmitRange
                    {
                        BeginRange = begin,
                        EndRange = end
                    });
                }
                else
                {
                    ranges = [
                      new TransmitRange
                      {
                          BeginRange = begin,
                          EndRange = end
                      }
                    ];
                    dics.Add(i, ranges);
                }
                begin = end;
            }
            foreach (KeyValuePair<long, List<TransmitRange>> i in dics)
            {
                transmits.Add(new Transmit
                {
                    Range = i.Value.ToArray(),
                    Scheme = config.Scheme,
                    ServerId = i.Key,
                    TransmitType = config.TransmitType
                });
            }
        }
        private void _InitZoneIndex (List<Transmit> transmits, ServerTransmitScheme config)
        {
            if (this._ServerId.Length == 1)
            {
                transmits.Add(new Transmit
                {
                    Range = new TransmitRange[]
                    {
                            new TransmitRange
                            {
                                BeginRange=48,
                                EndRange=128,
                                IsFixed=false
                            }
                    },
                    Scheme = config.Scheme,
                    TransmitType = config.TransmitType,
                    ServerId = this._ServerId[0]
                });
            }
            else
            {
                this._InitTransmit(_ZoneIndexSum, 48, 128, transmits, config);
            }
        }


        private void _AutoGenerate (List<Transmit> transmits, ServerTransmitScheme config)
        {
            if (config.TransmitType == TransmitType.HashCode)
            {
                this._InitHashCode(transmits, config);
            }
            else if (config.TransmitType == TransmitType.ZoneIndex)
            {
                this._InitZoneIndex(transmits, config);
            }
        }
    }
}
